//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
//==================================================================

#ifndef PWINDOW_H
#define PWINDOW_H

#include "psys.h"
#include "gadget.h"
#include "menu.h"
#include "fontuni.h"

//==================================================================
#ifndef _WINUSER_
#define VK_BACK           0x08
#define VK_TAB            0x09

#define VK_CLEAR          0x0C
#define VK_RETURN         0x0D

#define VK_SHIFT          0x10
#define VK_CONTROL        0x11

#define VK_ESCAPE         0x1B

#define VK_CONVERT        0x1C
#define VK_NONCONVERT     0x1D
#define VK_ACCEPT         0x1E
#define VK_MODECHANGE     0x1F

#define VK_SPACE          0x20
#define VK_PRIOR          0x21
#define VK_NEXT           0x22
#define VK_END            0x23
#define VK_HOME           0x24
#define VK_LEFT           0x25
#define VK_UP             0x26
#define VK_RIGHT          0x27
#define VK_DOWN           0x28
#define VK_SELECT         0x29
#define VK_PRINT          0x2A
#define VK_EXECUTE        0x2B
#define VK_SNAPSHOT       0x2C
#define VK_INSERT         0x2D
#define VK_DELETE         0x2E
#define VK_HELP           0x2F
#endif

//==================================================================
//==================================================================
enum win_flags
{
//	WIN_FLG_SHOW	= 1,
	WIN_FLG_NOFOCUS	= 2,
};

//==================================================================
enum win_init_flags
{
	WIN_INIT_FLG_OPENGL				= 1 << 8,
	WIN_INIT_FLG_DONT_CLEAR			= 2 << 8,
	WIN_INIT_FLG_INVISIBLE			= 4 << 8,
	WIN_INIT_FLG_SYSTEM				= 8 << 8,
	WIN_INIT_FLG_POPUP				= 16 << 8,
	WIN_INIT_FLG_CLIENTEDGE			= 32 << 8,
	WIN_INIT_FLG_TOOLWINDOW			= 64 << 8,
	WIN_INIT_FLG_HSCROLL			= 128 << 8,
	WIN_INIT_FLG_VSCROLL			= 256 << 8
};

//==================================================================
enum win_intflags
{
	WIN_FLG_MOUSE_CURSOR_IN			= 1,
	WIN_INTFLG_SENTENCED			= 4,
	WIN_INTFLG_CREATIONCOMPLETED	= 16,
	WIN_INTFLG_MOUSE_IN_CLIENT		= 32,

	WIN_INTFLG_OPENGL				= WIN_INIT_FLG_OPENGL,
	WIN_INTFLG_DONT_CLEAR			= WIN_INIT_FLG_DONT_CLEAR,
	WIN_INTFLG_INVISIBLE			= WIN_INIT_FLG_INVISIBLE,
	WIN_INTFLG_SYSTEM				= WIN_INIT_FLG_SYSTEM,
	WIN_INTFLG_POPUP				= WIN_INIT_FLG_POPUP,	
};

//==================================================================
class WindowEvent
{
public:
	//==================================================================
	enum Type
	{
		ETYPE_UNKNOWN,
		ETYPE_CREATE,
		ETYPE_ACTIVATE,
		ETYPE_DEACTIVATE,
		ETYPE_SHOW,
		ETYPE_PAINT,
		ETYPE_DESTROY,
		ETYPE_LBUTTONDOWN,
		ETYPE_LBUTTONUP,
		ETYPE_RBUTTONDOWN,
		ETYPE_RBUTTONUP,
		ETYPE_MOUSEMOVE,
		ETYPE_MOUSEMOVEDOUT,
		ETYPE_KEYDOWN,
		ETYPE_KEYUP,
		ETYPE_KEYCHAR,
		ETYPE_WINRESIZE,
		ETYPE_COMMAND,
		ETYPE_DROPFILES
	};

public:
	Type					type;
	int						mouse_x;
	int						mouse_y;
	int						mouse_lbutton;
	int						mouse_rbutton;
	int						keymod_ctrl, keymod_shift;
	u_short					keycode;
	TCHAR					keychar;
	bool					is_showing;
	int						win_w, win_h;
	class Window			*winp;
	u_int					command;

	std::vector<PSYS::tstring *> dropfiles;

	void					*ms_hwnd;
	u_int					ms_message;
	u_int					ms_wparam;
	u_int					ms_lparam;

	WindowEvent() :
		type(ETYPE_UNKNOWN),
		mouse_x(0),
		mouse_y(0),
		mouse_lbutton(0),
		mouse_rbutton(0),
		keymod_ctrl(0), keymod_shift(0),
		keycode(0),
		keychar(0),
		is_showing(0),
		win_w(0),
		win_h(0),
		winp(0),
		command(0),
		ms_hwnd(0),
		ms_message(0),
		ms_wparam(0),
		ms_lparam(0)
	{
	}

	~WindowEvent()
	{
		for (int i=0; i < dropfiles.size(); ++i)
			delete dropfiles[i];
	}

	const Type	GetType() const
	{
		return type;
	}

	//==================================================================
	typedef int	(*Callback)( void *objectp, WindowEvent *eventp );
};

#ifdef _WINDOWS_
typedef int (*win_mswin_eventfilter_t)( void *objectp, class Window *T, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
#else
typedef int (*win_mswin_eventfilter_t)( void *objectp, class Window *T, void *hWnd, unsigned int message, int wParam, int lParam );
#endif

//==================================================================
class Window
{
public:
	enum AnchorType
	{
		ANCH_TYPE_FIXED,
		ANCH_TYPE_PARENT_X1,
		ANCH_TYPE_PARENT_Y1,
		ANCH_TYPE_PARENT_X2,
		ANCH_TYPE_PARENT_Y2,
		ANCH_TYPE_THIS_X1,
		ANCH_TYPE_THIS_Y1,
		ANCH_TYPE_THIS_X2,
		ANCH_TYPE_THIS_Y2
	};

public:
	Window			*_nextp;
	Window			*_prevp;
	Window			*_childp;
	Window			*_parentp;

#ifdef _WINDOWS_
	HWND			_hwnd;
	HDC				_hdc;
	HGLRC			_hrc;
	win_mswin_eventfilter_t	_mswin_eventfilter;
#else
	void			*_hwnd;
	void			*_hdc;
	void			*_hrc;
	void			*_mswin_eventfilter;
#endif
	void			*_mswin_userdatap;

	TCHAR			_name[ 64 ];

	void			*_userobjectp;
	WindowEvent::Callback	_event_callback;

	AnchorType		_anch_typ[4];
	int				_anch_off[4];

	int				_x, _y, _w, _h;

	u_int			_flags;
	u_int			_intflags;

	int				_save_vport[4];

	WindowEvent		_event;

	GGET_Manager	_gget_manager;
	Menu			_main_menu;

public:
	Window();

	//==================================================================
	Window( const TCHAR *namep, Window *parentp,
			void *userobjectp, WindowEvent::Callback event_callback,
			int x, int y, int w, int h,
			win_init_flags flags,
			void *menu_id=0 );

	//==================================================================
	Window( const TCHAR *namep, Window *parentp,
			void *userobjectp, WindowEvent::Callback event_callback,
			AnchorType anch_type_x1, int anch_offset_x1,
			AnchorType anch_type_y1, int anch_offset_y1,
			AnchorType anch_type_x2, int anch_offset_x2,
			AnchorType anch_type_y2, int anch_offset_y2,
			win_init_flags flags,
			void *menu_id=0 );

	//==================================================================
	~Window();

	Menu	*GetMenu()
	{
		return &_main_menu;
	}

	int		GetWidth() const
	{
		return _w;
	}
	int		GetHeight() const
	{
		return _h;
	}

	GGET_Manager	&GetGGETManager()
	{
		return _gget_manager;
	}

	void	Reset();
	void	Invalidate();

	bool	IsMousePointerInside() const;

	void	SetMSWindowsEventFilter( const win_mswin_eventfilter_t evtfilterp )
	{
		_mswin_eventfilter = evtfilterp;
	}

	void	SetTitle( const TCHAR *titlep );
	void	SetFocus();
	void	Show( int onoff, bool do_minimize=false );
	bool	IsShowing() const;
	bool	IsIconic() const;
	void	Rethink();

	void	PostResize();



	//==================================================================
	void SetAnchorOffset_X1( int anch_offset )	{	_anch_off[0] = anch_offset;	}
	void SetAnchorOffset_Y1( int anch_offset )	{	_anch_off[1] = anch_offset;	}
	void SetAnchorOffset_X2( int anch_offset )	{	_anch_off[2] = anch_offset;	}
	void SetAnchorOffset_Y2( int anch_offset )	{	_anch_off[3] = anch_offset;	}

	void SetAnchorType_X1( AnchorType anch_type )	{	_anch_typ[0] = anch_type;	}
	void SetAnchorType_Y1( AnchorType anch_type )	{	_anch_typ[1] = anch_type;	}
	void SetAnchorType_X2( AnchorType anch_type )	{	_anch_typ[2] = anch_type;	}
	void SetAnchorType_Y2( AnchorType anch_type )	{	_anch_typ[3] = anch_type;	}

public:
	int eventFilter( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

private:
	void destroyWithChildren( WindowEvent *eventp );
	void ef_onDropFiles( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, WindowEvent &out_event );

	int get_anch_fixed_and_parent( AnchorType anch, int *outvalp, int val_idx );
	int get_anch_local_relative( AnchorType anch, int vals[4], int *outvalp, int val_idx );
};
typedef autodel<Window>	Window_SP;

//==================================================================
///
//==================================================================
namespace WinSys
{
#ifdef _WINDOWS_
	void		Init( HINSTANCE hinstance, HICON hicon, const TCHAR *win_classprefixp );
	HINSTANCE	GetInstance();
	void		GetDeskSize( u_int &out_wd, u_int &out_he );
	FontUni		&GetFont();
#endif

};

//==================================================================
class Window;

//==================================================================
PError win_init_quick( Window *T, const TCHAR *namep, Window *parentp,
					  void *userobjectp, WindowEvent::Callback event_callback,
					  int x, int y, int w, int h,
					  win_init_flags flags,
					  void *menu_id=0 );

//==================================================================
PError win_init_quick( Window *T, const TCHAR *namep, Window *parentp,
					  void *userobjectp, WindowEvent::Callback event_callback,
					  Window::AnchorType anch_type_x1, int anch_offset_x1,
					  Window::AnchorType anch_type_y1, int anch_offset_y1,
					  Window::AnchorType anch_type_x2, int anch_offset_x2,
					  Window::AnchorType anch_type_y2, int anch_offset_y2,
					  win_init_flags flags,
					  void *menu_id=0 );

//==================================================================
//void win_destroy( Window * T );
//void win_destroy_real( Window *T );
//void win_flags_set( Window *T, win_flags flags, int onoff );

int	 win_is_point_inside( Window *T, int px, int py );
//void win_globalpos_get( Window *T, int *xp, int *yp, int *wp, int *hp );
//void win_move( Window *T, int x, int y );
//void win_resize( Window *T, int w, int h );

void win_viewport_get( Window *T, int xywh[4] );

#ifdef _WINDOWS_
void win_mswin_event_callback_set( Window *T, win_mswin_eventfilter_t mswin_eventfilter, void *userdatap );
#endif

//==================================================================
//-- private
void win_post_event_perform( Window *winp );

//==================================================================
//==================================================================
//==================================================================
int		win_global_capture_set( Window *T );
void	win_global_capture_release( Window *T );
Window	*win_global_capture_get(void);

//==================================================================
void	win_vcursor_pos_getv( int pos[2] );
void	win_vcursor_pos_set( int x, int y );

void win_push_context( Window *T );
void win_pop_context();

#endif
